<?php

class APF_DB_DataObject {
    public static $enable_cache = true;

    public $cache_expire = 86400;

    public $isLoaded = false;

    public function __construct() {
        $this->init();
    }

    public function save() {
        $key = $this->key();
        if (!$this->isLoaded || is_null($this->$key)) {
            return $this->insert();
        } else {
            return $this->update();
        }
    }

    public function delete() {
        $primary_key = $this->get_primary_key();
        $class = get_called_class();
        if ($class::cache_enable()) $this->cache_delete();
        $accessor=static::get_accessor();
        return $accessor::use_model(get_class($this))->filter($this->key(), $primary_key)->delete();
    }

    protected function insert() {
        $accessor=static::get_accessor();
        $d = $accessor::use_model(get_class($this));
        foreach ($this->columns() as $objColumn => $dbColumn)
            if (!is_null($this->$objColumn))
                $d->set_field($objColumn, $this->$objColumn);
        $rs = $d->insert();
        $key = $this->key();
        if (is_null($this->$key))
            $this->$key = $d->connection->lastInsertId();
        //if (static::$enable_cache) $this->cache_update();//some insert use mysql default value, cache just get null...
        return $rs;
    }

    protected function update() {
        $primary_key = $this->get_primary_key();
        $class = get_called_class();
        if ($class::cache_enable()) $this->cache_update();
        $accessor=static::get_accessor();
        $d = $accessor::use_model(get_class($this));
        foreach ($this->columns() as $objColumn => $dbColumn)
            if (!is_null($this->$objColumn))
                $d->set_field($objColumn, $this->$objColumn);
        return $d->filter($this->key(), $primary_key)->update();
    }

    protected function cache_update() {
        APF::get_instance()->debug("update row cache");
        $cache = APF_Cache_Factory::get_instance()->get_memcache();
        $cache->set($cache->get_obj_key(get_called_class(), $this->get_primary_key()), $this, 0, $this->cache_expire);
    }

    protected function cache_delete() {
        APF::get_instance()->debug("delete row cache");
        $cache = APF_Cache_Factory::get_instance()->get_memcache();
        $cache->delete($cache->get_obj_key(get_called_class(), $this->get_primary_key()));
    }

    protected function init() {
        foreach ($this->columns() as $k => $v)
            $this->$k = null;
    }

    protected function key() {
        $mapping = static::get_mapping();
        return $mapping['key'];
    }

    protected function get_primary_key() {
        $key = $this->key();
        if (is_null($this->$key))
            throw new Exception('obj must have key first!', '010');
        return $this->$key;
    }

    protected function columns() {
        $mapping = static::get_mapping();
        return $mapping['columns'];
    }

    protected function table() {
        $mapping = static::get_mapping();
        return $mapping['table'];
    }

    public static function cache_enable() {
        return (static::$enable_cache && !APF::get_instance()->get_config('disable_obj_cache'));
    }

    public static function get_pdo_name($da) {
        if ($da->read_only && !$da->force_master)
                return static::get_pdo_slave_name();
        return static::get_pdo_master_name();
    }

    public static function get_pdo_slave_name() {
        throw new Exception('this function must be override', '009');
    }

    public static function get_pdo_master_name() {
        throw new Exception('this function must be override', '009');
    }

    public static function get_mapping() {
        throw new Exception('this function must be override', '009');
    }

    public static function data_access() {
        $accessor=static::get_accessor();
        return $accessor::use_model(get_called_class());
    }
    
    public static function get_accessor(){
        return 'APF_DB_MysqlAccessor';
    }

}
?>